package com.nodecollege.cloud.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.nodecollege.cloud.common.constants.NCConstants;
import com.nodecollege.cloud.common.model.NCResult;
import com.nodecollege.cloud.common.model.po.UpmsApi;
import com.nodecollege.cloud.common.model.po.UpmsApiVisit;
import com.nodecollege.cloud.common.model.po.UpmsTenant;
import com.nodecollege.cloud.common.model.vo.ApiVisitQuery;
import com.nodecollege.cloud.common.model.vo.ApiVisitVO;
import com.nodecollege.cloud.common.utils.DateUtils;
import com.nodecollege.cloud.common.utils.NCUtils;
import com.nodecollege.cloud.dao.mapper.UpmsApiVisitMapper;
import com.nodecollege.cloud.service.ApiService;
import com.nodecollege.cloud.service.ApiVisitService;
import com.nodecollege.cloud.service.TenantService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 接口访问
 *
 * @author LC
 * @date 2019/12/23 15:26
 */
@Service
public class ApiVisitServiceImpl implements ApiVisitService {

    private static final Logger logger = LoggerFactory.getLogger(ApiVisitServiceImpl.class);

    private Map<UpmsApiVisit, AtomicLong> visitMap = new ConcurrentHashMap<>(10000);

    @Autowired
    private Environment environment;

    @Autowired
    private ApiService apiService;

    @Autowired
    private TenantService tenantService;

    @Autowired
    private UpmsApiVisitMapper upmsApiVisitMapper;

    /**
     * 查询接口访问列表
     *
     * @param apiVisitQuery
     * @return
     */
    @Override
    public NCResult<ApiVisitVO> getApiVisitList(ApiVisitQuery apiVisitQuery) {
        List<UpmsApiVisit> list = new ArrayList<>();
        Long total = 0L;
        if (NCConstants.INT_NEGATIVE_1.equals(apiVisitQuery.getPageSize())) {
            list = upmsApiVisitMapper.selectApiVisitList(apiVisitQuery);
            total = NCUtils.isNullOrEmpty(list) ? 0 : Long.parseLong(list.size() + "");
        } else {
            Page page = PageHelper.startPage(apiVisitQuery.getPageNum(), apiVisitQuery.getPageSize());
            if (apiVisitQuery.isSort()) {
                page.setOrderBy(apiVisitQuery.getSortKey() + " " + apiVisitQuery.getSortDirection());
            }
            list = upmsApiVisitMapper.selectApiVisitList(apiVisitQuery);
            total = page.getTotal();
        }
        List<UpmsApi> apiList = apiService.getApiListCache();
        for (int j = 0; j < list.size(); j++) {
            for (int i = 0; i < apiList.size(); i++) {
                if (apiList.get(i).getApiId().equals(list.get(j).getApiId())) {
                    list.get(j).setApplicationName(apiList.get(i).getApplicationName());
                    list.get(j).setControllerName(apiList.get(i).getControllerName());
                    list.get(j).setModularName(apiList.get(i).getModularName());
                    list.get(j).setDescription(apiList.get(i).getDescription());
                    list.get(j).setApiUrl(apiList.get(i).getApiUrl());
                }
            }
        }
        List<UpmsTenant> tenantList = tenantService.getAllTenantListCache();
        List<ApiVisitVO> voList = new ArrayList<>((int) Math.ceil(list.size() / 0.75) + 1);
        for (int i = 0; i < list.size(); i++) {
            ApiVisitVO apiVisitVO = new ApiVisitVO();
            BeanUtils.copyProperties(list.get(i), apiVisitVO);
            voList.add(apiVisitVO);
        }
        for (int j = 0; j < voList.size(); j++) {
            for (int i = 0; i < tenantList.size(); i++) {
                if (tenantList.get(i).getTenantId().equals(voList.get(j).getTenantId())) {
                    voList.get(j).setTenantName(tenantList.get(i).getTenantName());
                }
            }
        }

        return NCResult.ok(voList, total);
    }

    /**
     * 添加接口访问记录
     *
     * @param upmsApiVisit
     */
    @Override
    public void addApiVisitCache(UpmsApiVisit upmsApiVisit) {
        // 1. 查出接口id
        List<UpmsApi> apiList = apiService.getApiListCache();
        for (int i = 0; i < apiList.size(); i++) {
            if (apiList.get(i).getApplicationName().equals(upmsApiVisit.getApplicationName())
                    && apiList.get(i).getControllerName().equals(upmsApiVisit.getControllerName())
                    && apiList.get(i).getApiUrl().equals(upmsApiVisit.getApiUrl())) {
                // 设置接口id
                upmsApiVisit.setApiId(apiList.get(i).getApiId());
                break;
            }
        }
        upmsApiVisit.setVisitDate(DateUtils.formatDate(new Date(), DateUtils.DATE_PATTERN.YYYYMMDD));
        upmsApiVisit.setVisitH(DateUtils.formatDate(new Date(), DateUtils.DATE_PATTERN.HH));
        InetAddress localHost = null;
        try {
            localHost = Inet4Address.getLocalHost();
        } catch (UnknownHostException e) {
            logger.error(e.getMessage(), e);
        }
        upmsApiVisit.setLocalIpPort(localHost.getHostAddress() + ":" + environment.getProperty("local.server.port"));

        if (!visitMap.containsKey(upmsApiVisit)) {
            visitMap.put(upmsApiVisit, new AtomicLong(0));
        }
        visitMap.get(upmsApiVisit).getAndIncrement();
    }

    /**
     * 添加接口访问记录
     *
     * @param apiVisitList
     */
    @Override
    public void addApiVisitList(List<UpmsApiVisit> apiVisitList) {
        for (int i = 0; i < apiVisitList.size(); i++) {
            upmsApiVisitMapper.insert(apiVisitList.get(i));
        }
    }

    /**
     * 每小时第一分钟的时候将上一个小时的数据保存到数据库中
     */
    @Scheduled(cron = "0 1 0/1 * * ? ")
    public void sync() {
        logger.info("#############   自动保存上一个小时的访问记录任务  启动   #############");
        Calendar now = Calendar.getInstance();
        now.setTime(new Date());
        now.add(Calendar.HOUR, -1);
        String dateH = DateUtils.formatDate(now.getTime(), DateUtils.DATE_PATTERN.HH);

        int initialCapacity = (int) Math.ceil(visitMap.size() / 0.75) + 1;
        List<UpmsApiVisit> oldList = new ArrayList<>(initialCapacity);
        Map<UpmsApiVisit, AtomicLong> nowMap = new ConcurrentHashMap(initialCapacity);
        for (Map.Entry<UpmsApiVisit, AtomicLong> entry : visitMap.entrySet()) {
            if (entry.getKey().getVisitH().equals(dateH)) {
                entry.getKey().setVisitCount(entry.getValue().get());
                oldList.add(entry.getKey());
            } else {
                nowMap.put(entry.getKey(), entry.getValue());
            }
        }
        visitMap = nowMap;
        for (int i = 0; i < oldList.size(); i++) {
            upmsApiVisitMapper.insert(oldList.get(i));
        }
        logger.info("#############   自动保存上一个小时的访问记录任务  结束   #############");
    }
}
